package com.wg.wuge.tulin.jmm;

import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockTest2 {

    public static void main(String[] args) {

        Queue queue = new Queue(5);
        new Thread(new Producer(queue)).start();
        new Thread(new Consumer(queue)).start();
    }
}

class Queue {

    private Object[] items;
    private int putIndex;
    private int takeIndex;
    private int size;
    private Condition notFull;
    private Condition notEmpty;
    private ReentrantLock lock;

    public Queue(int size) {
        lock = new ReentrantLock();
        items = new Object[size];
        notFull = lock.newCondition();
        notEmpty = lock.newCondition();
    }

    public void put(Object item) {
        lock.lock();
        try {
            while (size == items.length) {
                notFull.await();
            }
            items[putIndex] = item;
            if (++putIndex == items.length) {
                putIndex = 0;
            }
            ++size;
            notEmpty.signal();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            System.out.println("put " + item);
            lock.unlock();
        }
    }

    public Object take() {
        lock.lock();
        try {
            while (size == 0) {
                notEmpty.await();
            }
            Object item = items[takeIndex];
            if (++takeIndex == items.length) {
                takeIndex = 0;
            }
            --size;
            notFull.signal();
            return item;
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }
}

class Producer implements Runnable {
    private Queue queue;

    public Producer(Queue queue) {
        this.queue = queue;
    }

    @Override
    public void run() {

        try {
            while (true) {
                Thread.sleep(1000);
                queue.put(new Random().nextInt(1000));
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

    }
}

class Consumer implements Runnable {
    private Queue queue;

    public Consumer(Queue queue) {
        this.queue = queue;
    }

    @Override
    public void run() {

        try {
            while (true) {
                Thread.sleep(2000);
                System.out.println("xiaofei " + queue.take());
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }


}
